﻿using System;
using System.Windows.Input;
using System.Windows;
using System.Collections.Generic;

namespace Gmantis.Controls
{
    public class MouseHelper : IDisposable
    {
        // Fields
        private MouseEventHandler _contextMenuInvoked;
        private UIElement _element;
        private bool _isMouseOver;
        private Point _lastPos;
        private DateTime _lastTime;
        private List<object> _weakHandlers = new List<object>();
        private EventHandler<MouseWheelEventArgs> _wheel;
        private const string ERR_MUSTBEWINDOWLESS = "To use this event the Silverlight plug-in must have its 'windowless' parameter set to true.";

        // Events
        public event MouseEventHandler ContextMenuInvoked
        {
            add
            {
                this._contextMenuInvoked = (MouseEventHandler)Delegate.Combine(this._contextMenuInvoked, value);
                this.InitializeRightButton();
            }
            remove
            {
                this._contextMenuInvoked = (MouseEventHandler)Delegate.Remove(this._contextMenuInvoked, value);
            }
        }

        [Obsolete("Use C1TapHelper.Tapped instead.")]
        public event MouseEventHandler MouseClick;

        [Obsolete("Use C1TapHelper.DoubleTapped instead.")]
        public event MouseButtonEventHandler MouseDoubleClick;

        public event EventHandler<MouseWheelEventArgs> MouseWheel
        {
            add
            {
                this._wheel = (EventHandler<MouseWheelEventArgs>)Delegate.Combine(this._wheel, value);
                this.InitializeWheel();
            }
            remove
            {
                this._wheel = (EventHandler<MouseWheelEventArgs>)Delegate.Remove(this._wheel, value);
            }
        }

        // Methods
        public MouseHelper(UIElement element)
        {
            this._element = element;
            this._element.MouseEnter += new MouseEventHandler(this._element_MouseEnter);
            this._element.MouseLeave += new MouseEventHandler(this._element_MouseLeave);
            this.InitializeClick();
            this.InitializeDoubleClick();
            this.InitializeRightButton();
        }

        private void _element_MouseEnter(object sender, MouseEventArgs e)
        {
            this._isMouseOver = true;
        }

        private void _element_MouseLeave(object sender, MouseEventArgs e)
        {
            this._isMouseOver = false;
        }

        internal static void AddEventHandler(UIElement element, string eventName, Delegate handler)
        {
            element.GetType().GetEvent(eventName).AddEventHandler(element, handler);
        }

        private void ClickMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (this.MouseClick != null)
            {
                Point position = InputEventArgs.GetPosition(e, this._element);
                double num = this._lastPos.X - position.X;
                double num2 = this._lastPos.Y - position.Y;
                if (((num * num) + (num2 * num2)) > 4.0)
                {
                    this._lastTime = new DateTime();
                }
                if (e.Handled)
                {
                    this._lastPos = new Point();
                }
                else
                {
                    this._lastPos = InputEventArgs.GetPosition(e, this._element);
                }
            }
        }

        private void ClickMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (this.MouseClick != null)
            {
                DateTime now = DateTime.Now;
                Point position = InputEventArgs.GetPosition(e, this._element);
                double num = this._lastPos.X - position.X;
                double num2 = this._lastPos.Y - position.Y;
                if (((num * num) + (num2 * num2)) <= 4.0)
                {
                    this.MouseClick(this._element, e);
                }
            }
        }

        public void Dispose()
        {
            if (this._element != null)
            {
                this._element.MouseEnter -= new MouseEventHandler(this._element_MouseEnter);
                this._element.MouseLeave -= new MouseEventHandler(this._element_MouseLeave);
                this.FinalizeClick();
                this.FinalizeDoubleClick();
                this.FinalizeRightButton();
            }
        }

        private void DoubleClickMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (this.MouseDoubleClick != null)
            {
                DateTime now = DateTime.Now;
                Point position = InputEventArgs.GetPosition(e, this._element);
                if (now.Subtract(this._lastTime).TotalMilliseconds <= 400.0)
                {
                    double num = this._lastPos.X - position.X;
                    double num2 = this._lastPos.Y - position.Y;
                    if (((num * num) + (num2 * num2)) <= 4.0)
                    {
                        this.MouseDoubleClick(this._element, e);
                        return;
                    }
                }
                this._lastTime = now;
                this._lastPos = position;
            }
        }

        private void FinalizeClick()
        {
            RemoveEventHandler(this._element, "MouseLeftButtonDown", new MouseButtonEventHandler(this.ClickMouseLeftButtonDown));
            RemoveEventHandler(this._element, "MouseLeftButtonUp", new MouseButtonEventHandler(this.ClickMouseLeftButtonUp));
        }

        private void FinalizeDoubleClick()
        {
            RemoveEventHandler(this._element, "MouseLeftButtonDown", new MouseButtonEventHandler(this.DoubleClickMouseLeftButtonDown));
        }

        private void FinalizeRightButton()
        {
            this._element.MouseRightButtonDown -= new MouseButtonEventHandler(this.OnContextMenuInvoked);
        }

        private void InitializeClick()
        {
            this._lastPos = new Point();
            this._element.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.ClickMouseLeftButtonDown), true);
            AddEventHandler(this._element, "MouseLeftButtonUp", new MouseButtonEventHandler(this.ClickMouseLeftButtonUp));
        }

        private void InitializeDoubleClick()
        {
            this._lastPos = new Point();
            this._lastTime = new DateTime();
            AddEventHandler(this._element, "MouseLeftButtonDown", new MouseButtonEventHandler(this.DoubleClickMouseLeftButtonDown));
        }

        private void InitializeRightButton()
        {
            this._element.MouseRightButtonDown += new MouseButtonEventHandler(this.OnContextMenuInvoked);
        }

        private void InitializeWheel()
        {
            this._element.MouseWheel += delegate(object s, System.Windows.Input.MouseWheelEventArgs e)
            {
                if (this._isMouseOver && (this._wheel != null))
                {
                    MouseWheelEventArgs args = new MouseWheelEventArgs((double)(e.Delta / 120), e.GetPosition(this._element.GetRootVisual()))
                    {
                        Handled = e.Handled
                    };
                    this._wheel(this._element, args);
                    e.Handled = args.Handled;
                }
            };
        }

        private void OnContextMenuInvoked(object sender, MouseButtonEventArgs e)
        {
            if (this._isMouseOver && (this._contextMenuInvoked != null))
            {
                this._contextMenuInvoked(this._element, e);
                e.Handled = true;
            }
        }

        internal static void RemoveEventHandler(UIElement element, string eventName, Delegate handler)
        {
            element.GetType().GetEvent(eventName).RemoveEventHandler(element, handler);
        }

        private T WeakHandler<T>(T t)
        {
            this._weakHandlers.Add(t);
            return t;
        }
    }
}
